package com.showsu.editor.utils;

import com.showsu.editor.entity.Week;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.http.util.TextUtils;

import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DateUtil extends DateUtils {
	public static String DATE_FORMAT = "yyyy-MM-dd";
	public static String DATE_FORMAT_SIMPLE = "yyyyMMdd";
	public static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
	public static String DATE_FORMAT_CHINESE = "yyyy年M月d日";
	
	private static String[] parsePatterns = { 
    "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
    "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", 
    "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM" };

	public static String getDate(){
		return getDate(DateUtil.DATE_FORMAT);
	}
	
	public static String getDate(int index){
		return getDate(parsePatterns[index]);
	}

	public static String getDate(String pattern){
		return DateFormatUtils.format(new Date(), pattern);
	}

	public static String formatDate2yyyyMMdd(Date date){
		return formatDate(date, DATE_FORMAT_SIMPLE);
	}
	
	public static String formatDate(Date date){
		return formatDate(date, "");
	}

	public static String formatSecondsAsMMSS(long seconds) {
		long minutes = TimeUnit.SECONDS.toMinutes(seconds) ;
		long secs = seconds - TimeUnit.MINUTES.toSeconds(minutes);
		return String.format("%02d:%02d", minutes % 60, secs);
	}
	
	public static String formatDate(Date date, String pattern){
		if (StringUtil.isEmpty(date)) {
			date = new Date();
		} else if (StringUtil.isEmpty(pattern)) {
			pattern = DateUtil.DATE_FORMAT;
		}
		return DateFormatUtils.format(date, pattern);
	}

	public static String formatDateTime(Date date){
		return formatDate(date, DateUtil.DATE_TIME_FORMAT);
	}

	public static String getTime(){
		return formatDate(new Date(), "HH:mm:ss");
	}

	public static String getDateTime(){
	    return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
	}

	public static String getYear(){
		return formatDate(new Date(), "yyyy");
	}

	public static String getMonth(){
		return formatDate(new Date(), "MM");
	}

	public static String getDay(){
		return formatDate(new Date(), "dd");
	}

	public static String getHour(){
		return formatDate(new Date(), "HH");
	}

	public static int getHourInt(Date date){
		return Integer.parseInt(formatDate(date, "HH"));
	}

	public static String getWeek(){
		return formatDate(new Date(), "E");
	}
	//将日期字符串转换成Date格式
	public static Date parseDate(Object str){
	    if (str == null) {
			return null;
		}
	    try
	    {
	      return parseDate(str.toString(), parsePatterns); } catch (ParseException e) {
	    }
	    return null;
	}
	/*public static Date parseDate(Object str, int parsePatternsIndex){
	    if (str == null)
	      return null;
	    try
	    {
	      return parseDate(str.toString(), parsePatterns[parsePatternsIndex]); } catch (ParseException e) {
	    }
	    return null;
	}*/

	/**
	 * 与当前日期相差几天
	 * @param date
	 * @return
	 */
	public static long pastDays(Date date){
	    long t = new Date().getTime() - date.getTime();
	    return t / 86400000L;
	}
	/**
	 * 与当前日期相差几小时
	 * @param date
	 * @return
	 */
	public static long pastHour(Date date){
	    long t = new Date().getTime() - date.getTime();
	    return t / 3600000L;
	}
	/**
	 * 与当前日期相差几分钟
	 * @param date
	 * @return
	 */
	public static long pastMinutes(Date date){
	    long t = new Date().getTime() - date.getTime();
	    return t / 60000L;
	}

	public static String formatDateTime(long timeMillis){
	    long day = timeMillis / 86400000L;
	    long hour = timeMillis / 3600000L - day * 24L;
	    long min = timeMillis / 60000L - day * 24L * 60L - hour * 60L;
	    long s = timeMillis / 1000L - day * 24L * 60L * 60L - hour * 60L * 60L - min * 60L;
	    long sss = timeMillis - day * 24L * 60L * 60L * 1000L - hour * 60L * 60L * 1000L - min * 60L * 1000L - s * 1000L;
	    return (day > 0L ? day + "," : "") + hour + ":" + min + ":" + s + "." + sss;
	}

	/**
	 * 获取两个日期之间的天数
	 * @param before
	 * @param after
	 * @return
	 */
	public static double getDistanceOfTwoDate(Date before, Date after){
	    long beforeTime = before.getTime();
	    long afterTime = after.getTime();
	    return (afterTime - beforeTime) / 86400000L;
	}

	/**
	 * 获取两个日期之间的天数
	 * @param before
	 * @param after
	 * @return
	 */
	public static double getDistanceOfTwoDate(Long before, Long after){
		return (after - before) / 86400000L;
	}

	/**
	 * 获取两个时间之间的分钟数
	 * @param before
	 * @param after
	 * @return
	 */
	public static double getMinuteOfTwoDate(Date before, Date after) {
		long beforeTime = before.getTime();
		long afterTime = after.getTime();
		return (afterTime - beforeTime) / 1000 / 60;
	}

	/**
	 * 获取两个时间之间的分钟数
	 * @param before
	 * @param after
	 * @return
	 */
	public static double getMinuteOfTwoDate(Long before, Long after) {
		return (after - before) / 1000 / 60;
	}

	public static String addYear(Date date, int i, String pattern){
		return formatDate(i,3,date, pattern);
	}
	public static String addMonth(Date date, int i, String pattern){
		return formatDate(i,2,date, pattern);
	}
	public static String addDay(Date date, int i, String pattern){
		return formatDate(i,1,date, pattern);
	}

	public static Date addDay(Date date, int number){
		Calendar cal = Calendar.getInstance();
		if (date == null) {
			date = new Date();
		}
		cal.setTime(date);
		cal.add(Calendar.DATE, number);
		return cal.getTime();
	}

	public static Date addHour(Date date, int number){
		Calendar cal = Calendar.getInstance();
		if (date == null) {
			date = new Date();
		}
		cal.setTime(date);
		cal.add(Calendar.HOUR_OF_DAY, number);
		return cal.getTime();
	}

	public static Date addMinutes(Date date, int number){
		Calendar cal = Calendar.getInstance();
		if (date == null) {
			date = new Date();
		}
		cal.setTime(date);
		cal.add(Calendar.MINUTE, number);
		return cal.getTime();
	}


	/**
	 * 在当前日期上+number(年、月、日)
	 * @param number	日期增加number(年、月、日)
	 * @param type		控制类型(年type=3、月type=2、日type=1)
	 * @return
	 */
	private static String formatDate(int number, int type, Date date, String pattern){
		Calendar cal = Calendar.getInstance();
		if (date == null) {
			date = new Date();
		}
		cal.setTime(date);
		if (1 == type) {//操作日期(日)
			cal.add(Calendar.DATE, number);
		} else if (2 == type) {//操作日期(月)
			cal.add(Calendar.MONTH, number);
		} else if (3 == type) {//操作日期(年)
			cal.add(Calendar.YEAR, number);
		}
		return formatDate(cal.getTime(), pattern);
	}

	public static String getQuarter (String month) {
		String quarter = "";
		int m = Integer.parseInt(month);
		if (m >= 1 && m == 3) {
			quarter = "1";
		}
		if (m >= 4 && m <= 6) {
		quarter = "2";
		}
		if (m >= 7 && m <= 9) {
		quarter = "3";
		}
		if (m >= 10 && m <= 12) {
		quarter = "4";
		}
		return quarter;
	}

	/**
	 * 获取当天的开始时间
	 * @return
	 */
	public static Date getStartDateToday() {
		Calendar calendar = Calendar.getInstance();
		// 将小时、分钟、秒和毫秒设置为0，获取当天的开始时间
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	public static String getStartTodayStr() {
		// 获取当天的零点
		LocalDateTime startToday = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
		String yyyyMMddHHmmss = startToday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		return  yyyyMMddHHmmss;
	}

	/**
	 * 获取当天的开始时间
	 * @return
	 */
	public static Date getEndDateToday() {
		Calendar calendar = Calendar.getInstance();
		// 将小时、分钟、秒和毫秒设置为0，获取当天的开始时间
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
		return calendar.getTime();
	}

	public static String getEndTodayStr() {
		// 获取当天结束时间
		LocalDateTime endToday = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
		String yyyyMMddHHmmss = endToday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		return  yyyyMMddHHmmss;
	}

	/**
	 * 日期加时间添加，延长
	 * 如果会员在之前过期，新购买从当前时间计算；
	 * 如果未过期，怎在未到期的时间再加上购买的时间
	 * @param endTime
	 * @param validDays
	 * @return
	 */
	public static Date plusDays(Date endTime, Integer validDays) {
		Instant instant = endTime.toInstant();
		ZoneId zone = ZoneId.systemDefault();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
		if (localDateTime.isBefore(LocalDateTime.now())) {
			localDateTime = LocalDateTime.now();
		}
		LocalDateTime newTime = localDateTime.plusDays(validDays);
		Instant newInstant = newTime.atZone(zone).toInstant();
		Date newEndTime = Date.from(newInstant);
		return newEndTime;
	}

	/**
	 * 根据开始时间
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static List<Week> getWeekList(LocalDate startTime, LocalDate endTime) {
		List<Week> resultList = new ArrayList<Week>();
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");

		//判断是否同一周
		WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,4);
		if(startTime.get(weekFields.weekOfWeekBasedYear()) == endTime.get(weekFields.weekOfWeekBasedYear())){
			Week firstWeek = new Week();
			firstWeek.setDay(startTime + "~" + endTime);
			firstWeek.setStartTime(startTime);
			firstWeek.setEndTime(endTime);
			firstWeek.setStartTimeNumber(Integer.valueOf(df.format(startTime)));
			firstWeek.setEndTimeNumber(Integer.valueOf(df.format(endTime)));
			resultList.add(firstWeek);
			return resultList;
		}

		//开始周
		TemporalAdjuster FIRST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
		//开始周开始日期
		LocalDate startFirstWeek = startTime.with(FIRST_OF_WEEK);
		TemporalAdjuster LAST_OF_WEEK = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
		//开始周结束日期
		LocalDate endFirstWeek = startTime.with(LAST_OF_WEEK);


		//结束周
		TemporalAdjuster FIRST_OF_WEEK1 = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.minusDays(localDate.getDayOfWeek().getValue() - DayOfWeek.MONDAY.getValue()));
		LocalDate startLastWeek = endTime.with(FIRST_OF_WEEK1);
		TemporalAdjuster LAST_OF_WEEK1 = TemporalAdjusters.ofDateAdjuster(localDate -> localDate.plusDays(DayOfWeek.SUNDAY.getValue() - localDate.getDayOfWeek().getValue()));
		LocalDate endLastWeek = endTime.with(LAST_OF_WEEK1);

		//将第一周添加
		Week firstWeek = new Week();
		firstWeek.setDay(startTime + "~" + endFirstWeek);
		firstWeek.setStartTime(startTime);
		firstWeek.setEndTime(endFirstWeek);
		firstWeek.setStartTimeNumber(Integer.valueOf(df.format(startTime)));
		firstWeek.setEndTimeNumber(Integer.valueOf(df.format(endFirstWeek)));
		resultList.add(firstWeek);

		while (true) {
			startFirstWeek = startFirstWeek.plusDays(7);
			if (startFirstWeek.with(LAST_OF_WEEK).equals(startLastWeek.with(LAST_OF_WEEK1))) {
				break;
			} else {
				Week week = new Week();
				week.setDay(startFirstWeek.with(FIRST_OF_WEEK) + "~" + startFirstWeek.with(LAST_OF_WEEK));
				week.setStartTime(startFirstWeek.with(FIRST_OF_WEEK));
				week.setEndTime(startFirstWeek.with(LAST_OF_WEEK));
				week.setStartTimeNumber(Integer.valueOf(df.format(startFirstWeek.with(FIRST_OF_WEEK))));
				week.setEndTimeNumber(Integer.valueOf(df.format(startFirstWeek.with(LAST_OF_WEEK))));
				resultList.add(week);
				//System.out.println("日期="+startFirstWeek+"开始周="+startFirstWeek.with(FIRST_OF_WEEK)+"结束周="+startFirstWeek.with(LAST_OF_WEEK));
			}
		}
		Week lastWeek = new Week();
		lastWeek.setDay(startLastWeek + "~" + endTime);
		lastWeek.setStartTime(startLastWeek);
		lastWeek.setEndTime(endTime);
		lastWeek.setStartTimeNumber(Integer.valueOf(df.format(startLastWeek)));
		lastWeek.setEndTimeNumber(Integer.valueOf(df.format(endTime)));
		resultList.add(lastWeek);
		return resultList;
	}

	/**
	 * Java将Unix时间戳转换成指定格式日期字符串
	 * @param timestampL 时间戳 如：1659254916;
	 * @param formats 要格式化的格式 默认："yyyy-MM-dd HH:mm:ss";
	 *
	 * @return 返回结果 如："2016-09-05 16:06:42";
	 */
	public static Date TimeStamp2Date(Long timestampL, String formats) {
		if (TextUtils.isEmpty(formats)) {
			formats = "yyyy-MM-dd HH:mm:ss";
		}
		Long timestamp = timestampL * 1000;
//		String date = new SimpleDateFormat(formats, Locale.CHINA).format(new Date(timestamp));
		return new Date(timestamp);
	}

	/**
	 * 判断当前时间是否在输入的小时范围内
	 * @param timeRange 小时时间范围，固定格式：xx-xx，如08-18、22-09
	 * @return
	 */
	public static boolean checkTimeRangeAvailable(String timeRange) {
		if (StringUtils.isBlank(timeRange)) {
			return false;
		}
		//获取开始或结束的小时数字
		String[] timeRanges = timeRange.split(Constant.analyzeHit7);
		if (timeRanges.length != 2) {
			return false;
		}
		Integer start = null;
		Integer end = null;
		try {
			start = Integer.parseInt(timeRanges[0]);
			end = Integer.parseInt(timeRanges[1]);
		} catch (Exception e) {
			log.error("DateUtil.checkTimeRangeAvailable(String)获取开始/结束时间的小时数字异常, timeRange:{}" + timeRange, e);
			return false;
		}
		//如果end等于start，代表全天24小时
		if (end.equals(start)) {
			return true;
		}
		//如果end大于start，说明起止时间在同一天
		else if (end > start) {
			Date startTime = DateUtil.addHour(DateUtil.getStartDateToday(), start);
			Date endTime = DateUtil.addHour(DateUtil.getStartDateToday(), end);
			Long currentMillis = System.currentTimeMillis();
			if (currentMillis >= startTime.getTime() && currentMillis <= endTime.getTime()) {
				return true;
			}
		}
		//如果end小于start，说明起止时间跨天了
		else {
			Long currentMillis = System.currentTimeMillis();
			//第一种判断以开始时间为当天
			Date startTime0 = DateUtil.addHour(DateUtil.getStartDateToday(), start);
			Date endTime0 = DateUtil.addHour(DateUtil.getStartDateToday(), end + 24);
			if (currentMillis >= startTime0.getTime() && currentMillis <= endTime0.getTime()) {
				return true;
			}
			//第一种判断以结束时间为当天
			Date startTime1 = DateUtil.addHour(DateUtil.getStartDateToday(), start - 24);
			Date endTime1 = DateUtil.addHour(DateUtil.getStartDateToday(), end);
			if (currentMillis >= startTime1.getTime() && currentMillis <= endTime1.getTime()) {
				return true;
			}
		}
		return false;
	}
}